<template>
  <div
      v-if="visible"
      id="vue-picture-viewer"
      ref="vuePictureViewer"
      :style="maskContainer"
      @mouseup="removeMove()">
    <!-- 头部 -->
    <div class="perview-header">
      <span>{{ title }}</span>
    </div>
    <!-- 图片容器 -->
    <div
        ref="imgContainer"
        class="imgContainer">
      <img
          v-src="bigImgUrl"
          v-if="bigShowType.isImage"
          ref="bigImg"
          :style="
          'transform: scale(' +
            imgScale +
            ') rotate(' +
            imgRotate +
            'deg);margin-top:' +
            imgTop +
            'px;margin-left:' +
            imgLeft +
            'px;' +
            'max-width:80%;max-height:80%;'
        "
          alt=""
          @click.stop=""
          @mousedown="addMove">
      <div
          v-if="!bigShowType.isImage"
          class="file-show">
        <div v-if="!showPreviewBtn" class="title">该附件格式不支持预览，请下载后查看</div>
        <i
            class="el-icon-close"
            @click="closeViewer"/>
        <div class="content">
          <img
              :src="bigShowType.icon"
              class="file-icon">
          <div class="file-handle">
            <el-button
                v-if="showPreviewBtn"
                type="primary"
                plain
                @click="previewFile">预览
            </el-button>
            <el-button
                type="primary"
                @click="downloadFile">下载
            </el-button>
          </div>
        </div>
      </div>
      <!-- tips -->
      <transition name="fade">
        <div
            v-show="showTips"
            class="tips">{{ tipsText }}
        </div>
      </transition>
    </div>
    <div class="fixedHandle">
      <!-- 操作按钮 -->
      <flexbox
          v-if="bigShowType.isImage"
          class="handleContainer">
        <div class="handle-box">
          <i
              class="wk wk-zoom-in"
              @click="enlarge"/>
          <i
              class="wk wk-zoom-on"
              @click="reduce"/>
          <i
              class="wk wk-rotate"
              @click="rotate"/>
          <i
              class="wk wk-download"
              @click="downloadFile"/>
        </div>

        <div
            class="icon-btn"
            @click="closeViewer">
          <i class="el-icon-close"/>
        </div>
      </flexbox>

      <!-- 缩略图容器 -->
      <div
          v-if="imgLength > 1"
          class="thumbnailContainer">
        <ul>
          <li
              v-for="(item, index) in imgData"
              ref="thumbnailItem"
              :key="index"
              @click="switchImgUrl(index, $event)">
            <img
                v-src="item.url"
                v-if="isShowImage(item.name)"
                alt="">
            <img
                v-else
                :src="getFileTypeIconWithSuffix(item.name)"
                alt="">
          </li>
        </ul>
      </div>
    </div>
    <!-- 左边箭头 -->
    <div
        class="leftArrowCon"
        @click="handlePrev"
        @mouseenter="enterLeft"
        @mouseout="outLeft">
      <div
          v-show="leftArrowShow"
          class="icon-btn leftArrow">
        <i class="el-icon-arrow-left"/>
      </div>
    </div>
    <!-- 右边箭头 -->
    <div
        class="rightArrowCon"
        @click="handleNext"
        @mouseenter="enterRight"
        @mouseout="outRight">
      <div
          v-show="rightArrowShow"
          class="icon-btn rightArrow">
        <i class="el-icon-arrow-right"/>
      </div>
    </div>
  </div>
</template>


<script setup>
import {
  getMaxIndex,
  getFileIconWithSuffix,
  downloadFileWithBuffer,
  canPreviewFile,
  wkPreviewFile
  // getImageData
} from '/src/utils/index.js'
import {downloadFileAPI} from '/src/api/common.js'


import {computed, getCurrentInstance, nextTick, ref} from "vue";


// 引入消息总线
const cxt = getCurrentInstance() //相当于Vue2中的this
const bus = cxt.appContext.config.globalProperties.$bus


defineOptions({
  name: 'WkPreviewFile',

})


const visible = ref(false)
const imgData = ref([])
const background = ref('rgba(0,0,0,0.4)')
// 选择的索引
const selectIndex = ref(-1)
// 默认不显示左右切换箭头
const leftArrowShow = ref(false)
const rightArrowShow = ref(false)
// 图片容器数据
const bigShowType = ref({isImage: true, icon: ''}) // 不是图片的时候 展示 icon
const bigImgName = ref('')
const imgLength = ref(0)
const imgIndex = ref(0)
const showTips = ref(false)
const tipsText = ref('')
const maskContainer = ref({
  width: '100%',
  height: '100%',
  background: background.value,
  position: 'fixed',
  top: 0,
  left: 0,
  right: 0,
  bottom: 0
})
// 预览图片样式
const imgTop = ref(0)
const imgLeft = ref(0)
const imgScale = ref(1)
const imgRotate = ref(0)
const clientX = ref(0)
const clientY = ref(0)


const title = computed(() => {
  const fileName = bigImgName.value.slice(0, bigImgName.value.indexOf('.'))

  return `${fileName} （${imgIndex.value + 1} / ${imgLength.value}）`
})

const currentFile = computed(() => {
  return imgData.value[imgIndex.value]
})

const bigImgUrl = computed(() => {
  return currentFile.value.url
})

const showPreviewBtn = computed(() => {
  return canPreviewFile(currentFile.value.name)
})


/**
 * 预览
 */
function preview(data) {
  selectIndex.value = data.index
  imgData.value = data.data
  imgLength.value = imgData.value.length
  imgIndex.value = selectIndex.value
  visible.value = true

  nextTick(() => {
    const _dom = document.getElementById('vue-picture-viewer')
    _dom.onmousewheel = scrollFunc
    // 火狐浏览器没有onmousewheel事件，用DOMMouseScroll代替(滚轮事件)
    document.body.addEventListener('DOMMouseScroll', scrollFunc.value)
    // 禁止火狐浏览器下拖拽图片的默认事件
    document.ondragstart = function () {
      return false
    }

    document
        .getElementById('vue-picture-viewer')
        .addEventListener('click', e => {
          e.stopPropagation()
        })

    nextTick(() => {
      bigImgName.value = imgData.value[imgIndex.value].name
      getShowTypeInfo(bigImgName.value)

      if (imgLength.value > 1) {
        // 大于1的时候才会展示缩略图
        var item = cxt.refs.thumbnailItem
        item[imgIndex.value].className = 'borderActive'
      }

      init()
    })

    maskContainer.value['z-index'] = getMaxIndex()
  })
}

/**
 * init
 */
function init() {
  imgTop.value = 0
  imgLeft.value = 0
  imgScale.value = 1
  imgRotate.value = 0
  clientX.value = 0
  clientY.value = 0
}

/**
 * 放大
 */
function enlarge() {
  if (imgScale.value >= 5) return
  imgScale.value += 0.15
}

/**
 * 缩小
 */
function reduce() {
  if (imgScale.value <= 0.2) return

  imgScale.value -= 0.15
}

/**
 * 旋转
 */
function rotate() {
  imgRotate.value -= 90
}

/**
 * 点击缩略图切换图片
 */
function switchImgUrl(num, e) {
  var item = cxt.refs.thumbnailItem
  item.forEach(function (i) {
    i.className = ''
  })
  imgIndex.value = num
  bigImgName.value = imgData.value[num].name
  getShowTypeInfo(bigImgName.value)
  e.currentTarget.className = 'borderActive'
  if (bigShowType.value.isImage) {
    init()
  }
}

/**
 * 切换到上一张
 */
function handlePrev() {
  if (imgIndex.value <= 0) {
    tips('已经是第一张了!')
    imgIndex.value = 0
  } else {
    imgIndex.value--
    bigImgName.value = imgData.value[imgIndex.value].name
    getShowTypeInfo(bigImgName.value)

    var item = cxt.refs.thumbnailItem
    item.forEach(function (i) {
      i.className = ''
    })
    item[imgIndex.value].className = 'borderActive'
    if (bigShowType.value.isImage) {
      init()
    }
  }
}

/**
 * 切换到下一张
 */
function handleNext() {
  if (imgIndex.value + 1 >= imgData.value.length) {
    tips('已经是最后一张了!')
  } else {
    imgIndex.value++
    bigImgName.value = imgData.value[imgIndex.value].name
    getShowTypeInfo(bigImgName.value)

    var item = cxt.refs.thumbnailItem
    item.forEach(function (i) {
      i.className = ''
    })
    item[imgIndex.value].className = 'borderActive'
    if (bigShowType.value.isImage) {
      init()
    }
  }
}

/**
 * 提示框
 */
function tips(msg) {
  showTips.value = true
  tipsText.value = msg
  // const _this = this
  const _this = cxt
  setTimeout(function () {
    _this.showTips = false
  }, 10000)
}

/**
 * 鼠标左移
 */
function enterLeft() {
  leftArrowShow.value = true
}

function outLeft() {
  leftArrowShow.value = false
}

/**
 * 鼠标右移
 */
function enterRight() {
  rightArrowShow.value = true
}

function outRight() {
  rightArrowShow.value = false
}

/**
 * 关闭查看器
 */
function closeViewer() {
  if (document.getElementById('vue-picture-viewer')) {
    document
        .getElementById('vue-picture-viewer')
        .removeEventListener('click', e => {
          e.stopPropagation()
        })
    // 移除火狐浏览器下的鼠标滚动事件
    document.body.removeEventListener('DOMMouseScroll', scrollFunc.value)
    // 恢复火狐及Safari浏览器下的图片拖拽
    document.ondragstart = null
  }

  visible.value = false
  imgData.value = []
  selectIndex.value = -1
  showTips.value = false
}

/**
 * 附件逻辑
 */
function downloadFile() {
  downloadFileAPI(currentFile.value.url).then(res => {
    const blob = new Blob([res.data.data], {
      type: ''
    })
    downloadFileWithBuffer(blob, currentFile.value.name)
  }).catch(() => {
  })
}

function previewFile() {
  if (currentFile.value.url) {
    wkPreviewFile(currentFile.value.url, currentFile.value.name)
  }
}

function getShowTypeInfo(name) {
  const temps = name ? name.split('.') : []
  var ext = ''
  if (temps.length > 0) {
    ext = temps[temps.length - 1]
  } else {
    ext = ''
  }

  var icon = getFileIconWithSuffix(ext)
  var isImage = ['jpg', 'png', 'gif', 'jpeg'].includes(ext.toLowerCase())
  bigShowType.value = {isImage: isImage, icon: icon}
}

function getFileTypeIconWithSuffix(name) {
  const temps = name ? name.split('.') : []
  var ext = ''
  if (temps.length > 0) {
    ext = temps[temps.length - 1]
  } else {
    ext = ''
  }
  return getFileIconWithSuffix(ext)
}

function isShowImage(name) {
  const temps = name ? name.split('.') : []
  var ext = ''
  if (temps.length > 0) {
    ext = temps[temps.length - 1]
  } else {
    ext = ''
  }
  return ['jpg', 'png', 'gif', 'jpeg'].includes(ext.toLowerCase())
}

function removeMove() {
  cxt.refs.vuePictureViewer.onmousemove = null
}

/**
 * 鼠标按下
 */
function addMove(e) {
  e = e || window.event
  clientX.value = e.clientX
  clientY.value = e.clientY
  cxt.refs.vuePictureViewer.onmousemove = moveFunc.value
}

/**
 * 鼠标拖动
 */
function moveFunc(e) {
  e = e || window.event
  e.preventDefault()
  const movementX = e.clientX - clientX.value
  const movementY = e.clientY - clientY.value
  // event.clientY;
  imgLeft.value += movementX * 2
  imgTop.value += movementY * 2
  clientX.value = e.clientX
  clientY.value = e.clientY
}

/**
 * 鼠标滚轮缩放
 */
function scrollFunc(e) {
  e = e || window.event
  // e.returnValue = false // ie
  // 火狐下没有wheelDelta，用detail代替，由于detail值的正负和wheelDelta相反，所以取反
  e.delta = e.wheelDelta || -e.detail

  e.preventDefault()
  if (e.delta > 0) {
    // 当滑轮向上滚动时
    enlarge()
  }
  if (e.delta < 0) {
    // 当滑轮向下滚动时
    reduce()
  }
}
</script>

<style lang="scss" scoped>
.perview-header {
  width: 100%;
  height: 40px;
  background: rgba(0, 0, 0, 0.6);
  color: rgba(255, 255, 255, 0.8);
  line-height: 40px;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 101;
  padding: 10px;
  text-align: center;
  padding: 0 20px;
  cursor: pointer;
}

.leftArrowCon {
  width: 30%;
  height: calc(100% - 40px);
  background: transparent;
  position: absolute;
  top: 40px;
  left: 0;
  z-index: 98;
  cursor: pointer;
}

.rightArrowCon {
  width: 30%;
  height: calc(100% - 40px);
  background: transparent;
  position: absolute;
  top: 40px;
  right: 0;
  z-index: 99;
  cursor: pointer;
}

.leftArrow {
  position: absolute;
  top: 50%;
  left: 25%;
  margin-top: -60px;
  transition: all 0.5s;
  pointer-events: none;
}

.rightArrow {
  position: absolute;
  top: 50%;
  right: 25%;
  margin-top: -60px;
  transition: all 0.5s;
  pointer-events: none;
}

.imgContainer {
  width: 100%;
  height: 100%;
  text-align: center;
  vertical-align: middle;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: rgba(0, 0, 0, .3);
}

.imgContainer .tips {
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  text-align: center;
  line-height: 40px;
  position: absolute;
  left: 50%;
  top: 50%;
  min-width: 150px;
  margin-left: -60px;
  margin-top: -20px;
  border-radius: 6px;
  padding: 4px 4px;
  font-size: 14px;
}

.fixedHandle {
  width: 800px;
  height: 140px;
  position: fixed;
  left: 50%;
  bottom: 0;
  margin-left: -400px;
  overflow: hidden;
  z-index: 100;
}

.handleContainer {
  width: auto;
  position: absolute;
  left: 50%;
  bottom: 100px;
  margin-left: -150px;

  .handle-box {
    background: rgba(0, 0, 0, 0.6);
    height: 40px;
    line-height: 40px;
    border-radius: 20px;
    padding: 0 20px;
    margin-right: 30px;
    user-select: none;

    i {
      font-size: 20px;
      color: #fff;
      cursor: pointer;
    }

    i + i {
      margin-left: 15px;
    }
  }
}

// 图标按钮
.icon-btn {
  cursor: pointer;
  background: rgba(0, 0, 0, 0.6);
  color: white;
  width: 40px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  font-size: 20px;
  border-radius: 20px;

  i {
    font-weight: 600;
  }
}

.handleItem {
  width: 28px;
  height: 28px;
  color: white;
}

ul {
  padding: 0;
  margin: 0;
}

ul li {
  list-style: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin-left: 20px;
  cursor: pointer;
}

.thumbnailContainer {
  max-width: 800px;
  background: rgba(255, 255, 255, 0.7);
  position: absolute;
  left: 50%;
  bottom: 0;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
  transform: translate(-50%, 0%);
  overflow-x: auto;
  overflow-y: hidden;
}

.thumbnailContainer ul {
  padding-top: 10px;
  padding-bottom: 10px;
  text-align: center;
  white-space: nowrap;
}

.thumbnailContainer ul li {
  display: inline-block;
  width: 38px;
  height: 38px;
  box-sizing: content-box;
  margin-left: 10px;
  user-select: none;
}

.thumbnailContainer ul li:last-child {
  margin-right: 10px;
}

.thumbnailContainer ul li img {
  object-fit: contain;
  vertical-align: top;
  width: 100%;
  height: 100%;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 1s;
}

.fade-enter,
.fade-leave-to {
  opacity: 0;
}

/* 添加border */
.borderActive {
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.3);
}

/* 修改原生的滚动条 */
::-webkit-scrollbar {
  /* 血槽宽度 */
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-thumb {
  /* 拖动条 */
  background: rgba(0, 0, 0, 0.3);
  border-radius: 6px;
}

::-webkit-scrollbar-track {
  /* 背景槽 */
  background: #ddd;
  border-radius: 6px;
}

/** 文件展示*/
.file-show {
  position: absolute;
  top: 60%;
  left: 50%;
  width: 450px;
  height: 260px;
  margin-top: -150px;
  margin-left: -225px;
  background-color: white;
  border-radius: 3px;
  padding: 15px;

  .el-icon-close {
    position: absolute;
    top: 20px;
    right: 20px;
    font-size: 18px;
    font-weight: bold;
    color: #909399;
    cursor: pointer;
  }

  .el-icon-close:hover {
    color: $xr-color-primary;
  }

  .title {
    position: relative;
    font-size: 13px;
    color: #666;
    padding-left: 6px;
  }

  .title::before {
    content: '*';
    position: absolute;
    left: 0;
    top: 0;
    color: red;
  }

  .content {
    text-align: center;
    margin-top: 40px;

    .file-icon {
      width: 100px;
      width: 85px;
      vertical-align: middle;
    }

    .file-handle {
      width: 100px;
      margin-left: 50px;;
      margin-right: 0;
      vertical-align: middle;
      display: inline-block;

      .el-button {
        height: 34px;
        margin-left: 0;
      }

      .el-button + .el-button {
        margin-top: 8px;
      }
    }
  }
}
</style>
